package org.phalanx.gwt.client.screens;

import java.util.HashMap;
import java.util.Iterator;

import org.phalanx.gwt.client.graphics.PhalanxGraphicsConsole;
import org.phalanx.gwt.client.graphics.PhalanxMapEventListener;
import org.phalanx.gwt.client.graphics.PhalanxWebMapView;
import org.phalanx.gwt.client.graphics.map.MapCoordinates;
import org.phalanx.gwt.client.graphics.map.PhalanxMap;
import org.phalanx.gwt.client.graphics.map.PhalanxMapReader;
import org.phalanx.gwt.client.shared.MessageListener;
import org.phalanx.gwt.client.shared.MessageManager;
import org.phalanx.gwt.client.shared.PhalanxTeamPickerListBox;
import org.phalanx.gwt.client.shared.ServerMessage;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;

public class CreateGameScreen extends VerticalPanel implements ChangeHandler, MessageListener, ClickHandler, PhalanxMapEventListener {
	private TextBox gameName;
	private ListBox mapName;
	private HorizontalPanel mapPanel;
	private PhalanxWebMapView mapPreviewView;
	private ListBox numberOfPlayers;
	private ListBox turnMode;
	private TextBox numberOfSecondsPerTurn;
	private Label errorLabel;
	private Button createGame;
	private Button cancel;

	private MessageManager msgMgr;
	private ContextPanelChooser chooser;

	private HashMap<String,PhalanxMap> mapCacheTable;

	public static String PURE_TURN = "0";
	public static String PURE_TIME = "1";
	public static String MIXED = "2";


	public CreateGameScreen(MessageManager msgMgr, ContextPanelChooser chooser){
		this.msgMgr = msgMgr;
		this.chooser = chooser;
		mapCacheTable = new HashMap<String, PhalanxMap>();
	}

	public void init(){
		createComponents();
		initializePanel();
	}

	private void createComponents(){
		gameName = new TextBox();
		gameName.setText("Phalanx Game (" + getRandomNumber() + ")");

		errorLabel = new Label();
		errorLabel.setStylePrimaryName("errortext");

		// TODO: Get map list from server and when ready populate the drop down
		mapName = new ListBox();
		mapName.addItem("Pick a Map", "null");
		mapName.addItem("Ancient Greece");
		mapName.addItem("A River Runs Through it");
		mapName.addItem("kill death");
		mapName.addChangeHandler(this);

		numberOfPlayers = new ListBox();
		numberOfPlayers.setEnabled(false);

		turnMode = new ListBox();
		turnMode.addItem("Manual Turn", PURE_TURN);
		turnMode.addItem("Timer", PURE_TIME);
		turnMode.addItem("Both", MIXED);
		turnMode.addChangeHandler(this);

		numberOfSecondsPerTurn = new TextBox();
		numberOfSecondsPerTurn.setMaxLength(6);
		numberOfSecondsPerTurn.setEnabled(false);

		mapPanel = new HorizontalPanel();
		mapPanel.setVisible(false);

		createGame = new Button("Create Game");
		createGame.addClickHandler(this);

		cancel = new Button("Discard");
		cancel.addClickHandler(this);

		//mapPreviewView = null;
	}

	private void initializePanel(){
		//		mapPanel.add(mapPreviewView);

		this.add(mapPanel);

		this.add(new Label("Create new Game"));
		this.add(errorLabel);

		FlexTable settingsPanel = new FlexTable();
		settingsPanel.setWidth("320px");
		settingsPanel.setCellPadding(3);
		settingsPanel.setCellSpacing(5);

//		FlexCellFormatter cellFormatter = settingsPanel.getFlexCellFormatter();
		//		cellFormatter.setHorizontalAlignment(0, 1,
		//		        HasHorizontalAlignment.ALIGN_LEFT);


		//		settingsPanel.setWidget(0, 0, new Label("Game Title: "));
		//		settingsPanel.setWidget(0, 1, gameName);

		addRow("Game Title:", gameName, settingsPanel);
		addRow("Map: ", mapName, settingsPanel);
		addRow("Max Players: ", numberOfPlayers, settingsPanel);
		addRow("Get Turn Mode: ", turnMode, settingsPanel);
		addRow("Get Turn Time (sec): ", numberOfSecondsPerTurn, settingsPanel);

		HorizontalPanel buttonPanel = new HorizontalPanel();
		buttonPanel.setSpacing(5);
		buttonPanel.add(createGame);
		buttonPanel.add(cancel);

		addRow(null, buttonPanel, settingsPanel);

		/*settingsPanel.setWidget(1, 0, new Label("Map: "));
		settingsPanel.setWidget(1, 1, mapName);

		settingsPanel.setWidget(2, 0, new Label("Max Players: "));
		settingsPanel.setWidget(2, 1, numberOfPlayers);

		settingsPanel.setWidget(3, 0, new Label("Player Alias: "));
		settingsPanel.setWidget(3, 1, gameNameAlias);
		 */
		this.add(settingsPanel);
	}

	private void addRow(String labelText, Widget w, FlexTable table){
		Integer rowNumber = table.getRowCount();

		table.getFlexCellFormatter().setHorizontalAlignment(rowNumber, 0, HasHorizontalAlignment.ALIGN_LEFT);
		table.getFlexCellFormatter().setHorizontalAlignment(rowNumber, 1, HasHorizontalAlignment.ALIGN_LEFT);

		if (labelText == null && w != null){
			table.getFlexCellFormatter().setColSpan(rowNumber, 0, 2);
			table.setWidget(rowNumber, 0, w);
		} else if (w == null){
			table.getFlexCellFormatter().setColSpan(rowNumber, 0, 2);
			table.setWidget(rowNumber, 0, new Label(labelText));
		} else {
			table.setWidget(rowNumber, 0, new Label(labelText));
			table.setWidget(rowNumber, 1, w);
		}
	}

	private int getRandomNumber(){
		return Math.abs((Random.nextInt() % (99999 - 10000)) + 10000);
	}

	@Override
	public void onChange(ChangeEvent event) {
		if (event.getSource().equals(mapName)){
			String mapNameValue = mapName.getValue(mapName.getSelectedIndex());

			if (mapNameValue.equals("null")){
				mapPanel.setVisible(false);

				numberOfPlayers.clear();
				numberOfPlayers.setEnabled(false);
				
				mapPreviewView.removePhalanxMapEventListener(this);
			}
			else {
				PhalanxMap pMap = getMapFromTemporaryCache(mapNameValue);

				if (pMap != null){
					renderMapPanel(pMap);
				} else {
					ServerMessage getMapMsg = new ServerMessage();
					getMapMsg.setContext("loadmap");
					getMapMsg.addMessageContents("mapname", mapNameValue);
					getMapMsg.setGET();

					msgMgr.sendMessage(getMapMsg);
					msgMgr.addMessageListener("mapdownload", this);
				}
			}
		} else if (event.getSource().equals(turnMode)){
			toggleTurnMode();
		}
	}

	//	private void handleBuildPointSelection(){
	//		String bpSelection = buildPoint.getValue(buildPoint.getSelectedIndex());
	//
	//		if (bpSelection != null && !bpSelection.isEmpty()){
	//			bpSelection = bpSelection.substring(1, bpSelection.length() - 1);
	//
	//			String[] xyCoor = bpSelection.split(",");
	//
	//			if (xyCoor.length > 1){
	//				Integer coor1 = Integer.valueOf(xyCoor[0]);
	//				Integer coor2 = Integer.valueOf(xyCoor[1]);
	//
	//				if (mapPreviewView != null){
	//					mapPreviewView.setCoordinates(coor1, coor2);
	//					mapPreviewView.renderMap();
	//				}
	//			}
	//		}
	//	}

	private void toggleTurnMode(){
		String turnModeValue = turnMode.getValue(turnMode.getSelectedIndex());

		if (turnModeValue.equals(PURE_TURN)){
			numberOfSecondsPerTurn.setText("");
			numberOfSecondsPerTurn.setEnabled(false);
		} else {
			numberOfSecondsPerTurn.setEnabled(true);
		}
	}

	@Override
	public void onMessageReceived(ServerMessage msg) {
		if (msg.getContext().equals("mapdownload")){
			PhalanxMapReader pMapReader = new PhalanxMapReader();
			pMapReader.setMapData(msg);
			PhalanxMap pMap = pMapReader.getMap();

			if (pMap != null){
				renderMapPanel(pMap);
				mapCacheTable.put(pMap.getMapName(), pMap); // Keep it stored in cache
			}

			msgMgr.removeMessageListener("mapdownload", this);
		}
		if (msg.getContext().equals("creategame")){
			msgMgr.removeMessageListener("creategame", this);
			String statusMsg = msg.getMessageContentsValue("status");

			if (statusMsg != null && statusMsg.equals("fail")){
				errorLabel.setText("Error creating game");
			} else {
				// Start joining game

				String gameid = msg.getMessageContentsValue("gameid");
//
//				ServerMessage joinGame = new ServerMessage();
//				joinGame.setContext("game");
//				joinGame.addMessageContents("action", "joinpregame");
//
//				joinGame.addMessageContents("gameid", gameid);
//
//				msgMgr.sendMessage(joinGame);
				
				JoinGameScreen jScreen = new JoinGameScreen(msgMgr, chooser);
				jScreen.setMap(mapPreviewView.getMap());
				jScreen.initializeJoin(Integer.valueOf(gameid));
				chooser.addPanelToChooser(gameid, jScreen);
				chooser.removePanelFromChooser("newgame");
				chooser.setContextPanel(gameid);
			}
		} 
	}

	private void renderMapPanel(PhalanxMap pMap){
		mapPreviewView = new PhalanxWebMapView(pMap, 200, 400);
		mapPreviewView.setZoomLevel(PhalanxWebMapView.ZOOMOUT_LEVEL_2);
		mapPreviewView.renderMap();

		mapPanel.clear();
		mapPanel.add(mapPreviewView);
		mapPanel.setVisible(true);

		numberOfPlayers.setEnabled(true);
		numberOfPlayers.clear();
		
		mapPreviewView.addPhalanxMapEventListener(this);

				if (pMap.getBuildPoints().size() > 1){
					for (int i = 1; i < pMap.getBuildPoints().size(); i++){
						numberOfPlayers.addItem((i + 1) + " players", (i + 1) + "");
					}
				}
		//
		//			buildPoint.clear();
		//
		//			buildPoint.addItem("Select Build Point", "null");
		//
		//			Iterator<MapCoordinates> i = pMap.getBuildPoints().iterator();
		//
		//			while (i.hasNext()){
		//				MapCoordinates c = i.next();
		//
		//				String bpFaceValue = "(" + c.getX() + "," + c.getY() + ")";
		//
		//				buildPoint.addItem(bpFaceValue);
		//			}
		//
		//			if (buildPoint.getItemCount() > 0){
		//				buildPoint.setEnabled(true);
		//			}
		//		}
	}

	private PhalanxMap getMapFromTemporaryCache(String mapName){
		return mapCacheTable.get(mapName);
	}

	@Override
	public void onClick(ClickEvent event) {
		Object clickedWidget = event.getSource();

		if (clickedWidget.equals(createGame)){
			String validString = isValid();

			if (validString.equals("OK")){
				// Create game
				ServerMessage createGameMsg = new ServerMessage();
				createGameMsg.setContext("game");
				createGameMsg.addMessageContents("action", "creategame");
				createGameMsg.addMessageContents("gamename", gameName.getText());
				createGameMsg.addMessageContents("mapname", mapName.getValue(mapName.getSelectedIndex()));
				String turnModeValue = turnMode.getValue(turnMode.getSelectedIndex());
				createGameMsg.addMessageContents("turnmode", turnModeValue);

				if (!turnModeValue.equals(PURE_TURN)){
					createGameMsg.addMessageContents("timer", numberOfSecondsPerTurn.getText());
				}

				createGameMsg.addMessageContents("maxplayers", numberOfPlayers.getValue(numberOfPlayers.getSelectedIndex()));

				msgMgr.addMessageListener("creategame", this);
				msgMgr.sendMessage(createGameMsg);
			} else {
				errorLabel.setText(validString);
			}
		}
		else if (clickedWidget.equals(cancel)){
			// Discard and go back to previous panel

			String lastPanel = chooser.getLastContextPanelName();

			if (lastPanel != null){
				if (chooser.getContextPanel(lastPanel) != null){
					chooser.setContextPanel(lastPanel);
					chooser.removePanelFromChooser("newgame");
				} else {
					chooser.setContextPanel("home");
				}
			}
		}
	}

	private String isValid(){
		// Sanity check of inputs
		String isValidated = "OK";

		String mapNameValue = mapName.getValue(mapName.getSelectedIndex());
		String turnModeValue = turnMode.getValue(turnMode.getSelectedIndex());

		if (mapNameValue.equals("null")){
			isValidated = "No Map Selected";
		} else {
			if (!turnModeValue.equals(PURE_TURN)){
				if (numberOfSecondsPerTurn.getText().isEmpty()){
					isValidated = "Please specify seconds";
				}else {
					try {
						Integer seconds = Integer.valueOf(numberOfSecondsPerTurn.getText());

						if (seconds <= 60 || seconds > 86400){
							isValidated = "Timer must be between 60 and 86400 seconds";
						}
					} catch (NumberFormatException nfe){
						isValidated = "Invalid seconds value";
					}
				}
			} 
		}
		return isValidated;
	}

	@Override
	public void onPhalanxMapTriggeredEvent(Event event,
			PhalanxGraphicsConsole source) {
		if (mapPreviewView.getMap() != null){
			Integer xVal = mapPreviewView.getRelativePixelPositionX(event.getClientX());
			Integer yVal = mapPreviewView.getRelativePixelPositionY(event.getClientY());
			
			mapPreviewView.setCoordinates(xVal, yVal);
			mapPreviewView.renderMap();
		}
	}
}
